package reflect;

import java.lang.reflect.Constructor;
import java.util.Arrays;

/**
 * 反射的使用
 * 所有和反射相关的包都在import java.lang.reflect包下
 */
public class ReflectClass {
    public static void main(String[] args) throws Exception { // 许多方法都会抛出异常所以这里直接抛出异常类就好
        // 第一步：都要先获取类的对象
        // 1.直接通过 类名称.class获取该类的对象
        Class<Student> cls1 = Student.class;

        // 2.1调用class对象的newInstance（）方法产生Student类的实例
        // 默认调用该类的无参构造，如果没有无参构造方法或者不可见时无法使用该方法产生类的实例
        Student stu = cls1.newInstance();
        System.out.println(stu); // Student{name='cup', age=19}

        // 2.2想要通过其他构造方法来产生Student类的实例，需要用到和构造方法结构相关的
        // cls.getDeclaredConstructor()方法可以获取该类所有构造方法 甚至不可见 的构造方法
        Constructor<Student> constructor = cls1.getDeclaredConstructor(); // 拿到的是无参构造的Constructor对象
        // 然后就可以使用con.new Instance()创建该类的实例
        Student stu1 = constructor.newInstance();
        System.out.println(stu1);

        // 如果该无参构造方法不可见需要使用.setAccessible(true)方法来 破坏封装
        Constructor<Student> constructor1 = cls1.getDeclaredConstructor(String.class, int.class);
        constructor1.setAccessible(true); // 破坏封装，但仅限constructor1使用
        Student stu2 = constructor1.newInstance("ww", 10);
        System.out.println(stu2); // 结果：Person类的无参构造方法  Student的私有的有参构造方法  Student{name='ww', age=10}

        // 2.3使用cls.getConstructors()方法可以获取当前类的 所有 public 权限的构造方法
        Constructor<?>[] constructor2 = cls1.getConstructors(); // 获取到的是一个集合
        System.out.println(Arrays.toString(constructor2)); // [public reflect.Student(java.lang.String,double), public reflect.Student()]
        Student stu3 = (Student) constructor2[1].newInstance(); // 前面钻石括号中的泛型如果是问号的话需要强转为Student
        Student stu4 = (Student) constructor2[0].newInstance("kk", 180.3);
        System.out.println(stu3);
        System.out.println(stu4);

        // 2.4使用cls.getConstructor()方法可以获取一个Constructor实例化对象，通过参数按到不同public构造方法
        Constructor<Student> constructor3 = cls1.getConstructor(); // 拿到无参构造方法
        Constructor<Student> constructor4 = cls1.getConstructor(String.class, double.class); // 拿到两个参数的构造方法
        Student stu5 = constructor4.newInstance("uu", 160);
        System.out.println(stu5);
    }
}
